package com.zhentao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhentao.pojo.SysRole;
import com.zhentao.pojo.SysUser;
import com.zhentao.pojo.SysUserRole;
import com.zhentao.service.AuthService;
import com.zhentao.service.SysRoleService;
import com.zhentao.service.SysUserRoleService;
import com.zhentao.service.SysUserService;
import com.zhentao.utils.JwtUtil;
import com.zhentao.vo.LoginVO;
import com.zhentao.vo.PhoneLoginVO;
import com.zhentao.vo.RegisterVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.zhentao.config.SmsConfig;
import com.zhentao.utils.HttpUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final SysUserService sysUserService;
    private final SysRoleService sysRoleService;
    private final SysUserRoleService sysUserRoleService;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    private final StringRedisTemplate redisTemplate;
    private final SmsConfig smsConfig;

    private static final String VERIFY_CODE_PREFIX = "verify_code:";
    private static final long VERIFY_CODE_EXPIRE = 300; // 验证码有效期5分钟
    private static final Random RANDOM = new Random();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(RegisterVO registerVO) {
        // 1. 校验用户名是否存在
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, registerVO.getUsername());
        if (sysUserService.count(wrapper) > 0) {
            throw new RuntimeException("用户名已存在");
        }

        // 2. 校验角色ID
        if (registerVO.getRid() == null) {
            throw new RuntimeException("角色ID不能为空");
        }
        if (registerVO.getRid() != 1L && registerVO.getRid() != 2L) {
            throw new RuntimeException("无效的角色ID，只能是1(管理员)或2(普通用户)");
        }

        // 3. 保存用户信息
        SysUser sysUser = new SysUser();
        sysUser.setUsername(registerVO.getUsername());
        sysUser.setPassword(passwordEncoder.encode(registerVO.getPassword()));
        sysUser.setName(registerVO.getName());
        sysUser.setPhone(registerVO.getPhone());
        sysUser.setStatus(1);
        sysUser.setCreateTime(String.valueOf(new Date()));
        sysUser.setUpdateTime(String.valueOf(new Date()));
        sysUser.setIsDeleted(0);
        sysUserService.save(sysUser);
        log.debug("用户信息保存成功: {}", sysUser);

        // 4. 根据rid获取对应的角色
        String roleCode = registerVO.getRid() == 1L ? "ROLE_ADMIN" : "ROLE_USER";
        LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysRole::getRoleCode, roleCode)
                  .eq(SysRole::getIsDeleted, 0);
        SysRole sysRole = sysRoleService.getOne(roleWrapper);
        if (sysRole == null) {
            throw new RuntimeException("角色不存在");
        }
        log.debug("查询到角色信息: {}", sysRole);

        // 5. 保存用户角色关系
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(sysUser.getId());
        userRole.setRoleId(sysRole.getId());
        userRole.setCreateTime(new Date());
        userRole.setUpdateTime(new Date());
        userRole.setIsDeleted(0);
        sysUserRoleService.save(userRole);
        log.debug("用户角色关系保存成功: {}", userRole);

        log.info("用户注册成功: {}, 角色: {}", registerVO.getUsername(), roleCode);
    }

    @Override
    public String login(LoginVO loginVO) {
        // 1. 校验角色ID
        if (loginVO.getRid() == null) {
            throw new RuntimeException("角色ID不能为空");
        }
        if (loginVO.getRid() != 1L && loginVO.getRid() != 2L) {
            throw new RuntimeException("无效的角色ID，只能是1(管理员)或2(普通用户)");
        }

        // 2. 根据用户名查询用户
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, loginVO.getUsername())
              .eq(SysUser::getIsDeleted, 0);
        SysUser sysUser = sysUserService.getOne(wrapper);
        if (sysUser == null) {
            throw new RuntimeException("用户名不存在");
        }

        // 3. 校验密码
        if (!passwordEncoder.matches(loginVO.getPassword(), sysUser.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // 4. 校验用户状态
        if (sysUser.getStatus() == 0) {
            throw new RuntimeException("用户已被禁用");
        }

        // 5. 校验用户角色
        String roleCode = loginVO.getRid() == 1L ? "ROLE_ADMIN" : "ROLE_USER";
        LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(SysRole::getRoleCode, roleCode)
                  .eq(SysRole::getIsDeleted, 0);
        SysRole role = sysRoleService.getOne(roleWrapper);
        if (role == null) {
            throw new RuntimeException("角色不存在");
        }

        // 6. 验证用户是否拥有该角色
        LambdaQueryWrapper<SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
        userRoleWrapper.eq(SysUserRole::getUserId, sysUser.getId())
                .eq(SysUserRole::getRoleId, role.getId())
                .eq(SysUserRole::getIsDeleted, 0);
        if (sysUserRoleService.count(userRoleWrapper) == 0) {
            throw new RuntimeException("您没有该角色的权限");
        }

        log.info("用户登录成功: {}, 角色: {}", loginVO.getUsername(), roleCode);
        // 7. 生成JWT token
        return jwtUtil.generateToken(sysUser.getUsername(), loginVO.getRid(),sysUser.getId());
    }

    @Override
    public String phoneLogin(PhoneLoginVO phoneLoginVO) {
        log.info("开始手机验证码登录流程，手机号: {}", phoneLoginVO.getPhone());

        // 1. 校验角色ID
        if (phoneLoginVO.getRid() == null) {
            throw new RuntimeException("角色ID不能为空");
        }
        if (phoneLoginVO.getRid() != 1L && phoneLoginVO.getRid() != 2L) {
            throw new RuntimeException("无效的角色ID，只能是1(管理员)或2(普通用户)");
        }

        // 2. 校验手机号格式
        if (!StringUtils.hasText(phoneLoginVO.getPhone()) ||
            !phoneLoginVO.getPhone().matches("^1[3-9]\\d{9}$")) {
            throw new RuntimeException("无效的手机号格式");
        }

        // 3. 校验验证码
        String redisKey = VERIFY_CODE_PREFIX + phoneLoginVO.getPhone();
        String cacheCode = redisTemplate.opsForValue().get(redisKey);
        log.info("从Redis获取验证码，key: {}, 存储的验证码: {}, 用户输入的验证码: {}",
                redisKey, cacheCode, phoneLoginVO.getCode());

        if (!StringUtils.hasText(cacheCode)) {
            log.error("验证码不存在或已过期，key: {}", redisKey);
            throw new RuntimeException("验证码已过期");
        }
        if (!cacheCode.equals(phoneLoginVO.getCode())) {
            log.error("验证码不匹配，期望: {}, 实际: {}", cacheCode, phoneLoginVO.getCode());
            throw new RuntimeException("验证码错误");
        }

        // 4. 查询用户
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getPhone, phoneLoginVO.getPhone())
              .eq(SysUser::getIsDeleted, 0);
        SysUser sysUser = sysUserService.getOne(wrapper);

        // 5. 如果用户不存在，自动注册
        if (sysUser == null) {
            sysUser = new SysUser();
            sysUser.setPhone(phoneLoginVO.getPhone());
            sysUser.setUsername(phoneLoginVO.getPhone()); // 使用手机号作为用户名
            sysUser.setStatus(1);
            sysUser.setCreateTime(String.valueOf(new Date()));
            sysUser.setUpdateTime(String.valueOf(new Date()));
            sysUser.setIsDeleted(0);
            sysUserService.save(sysUser);

            // 6. 关联角色
            String roleCode = phoneLoginVO.getRid() == 1L ? "ROLE_ADMIN" : "ROLE_USER";
            LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
            roleWrapper.eq(SysRole::getRoleCode, roleCode)
                      .eq(SysRole::getIsDeleted, 0);
            SysRole sysRole = sysRoleService.getOne(roleWrapper);
            if (sysRole == null) {
                throw new RuntimeException("角色不存在");
            }

            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(sysUser.getId());
            userRole.setRoleId(sysRole.getId());
            userRole.setCreateTime(new Date());
            userRole.setUpdateTime(new Date());
            userRole.setIsDeleted(0);
            sysUserRoleService.save(userRole);
        } else {
            // 7. 校验用户状态
            if (sysUser.getStatus() == 0) {
                throw new RuntimeException("用户已被禁用");
            }

            // 8. 校验用户角色
            String roleCode = phoneLoginVO.getRid() == 1L ? "ROLE_ADMIN" : "ROLE_USER";
            LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
            roleWrapper.eq(SysRole::getRoleCode, roleCode)
                      .eq(SysRole::getIsDeleted, 0);
            SysRole role = sysRoleService.getOne(roleWrapper);
            if (role == null) {
                throw new RuntimeException("角色不存在");
            }

            // 9. 验证用户是否拥有该角色
            LambdaQueryWrapper<SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
            userRoleWrapper.eq(SysUserRole::getUserId, sysUser.getId())
                    .eq(SysUserRole::getRoleId, role.getId())
                    .eq(SysUserRole::getIsDeleted, 0);
            if (sysUserRoleService.count(userRoleWrapper) == 0) {
                throw new RuntimeException("您没有该角色的权限");
            }
        }

        // 10. 删除验证码
        redisTemplate.delete(redisKey);

        // 11. 生成JWT token
        log.info("手机号登录成功: {}, 角色: {}", phoneLoginVO.getPhone(),
                phoneLoginVO.getRid() == 1L ? "管理员" : "普通用户");
        return jwtUtil.generateToken(sysUser.getUsername(), phoneLoginVO.getRid(), sysUser.getId());
    }

    @Override
    public void sendVerificationCode(String phone) {
        log.info("开始发送验证码流程，手机号: {}", phone);

        // 1. 校验手机号格式
        if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) {
            log.error("手机号格式错误: {}", phone);
            throw new RuntimeException("无效的手机号格式");
        }

        // 2. 生成6位随机验证码
        String code = String.format("%06d", RANDOM.nextInt(1000000));
        log.info("生成验证码: {}", code);

        try {
            // 3. 准备请求参数
            Map<String, String> headers = new HashMap<>();
            headers.put("Authorization", "APPCODE " + smsConfig.getAppCode());
            headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

            Map<String, String> bodys = new HashMap<>();
            bodys.put("content", "code:" + code);
            bodys.put("template_id", smsConfig.getTemplateId());
            bodys.put("phone_number", phone);

            log.info("准备发送短信，参数: headers={}, body={}", headers, bodys);

            // 4. 发送短信
            HttpResponse response = HttpUtils.doPost(
                smsConfig.getHost(),
                smsConfig.getPath(),
                smsConfig.getMethod(),
                headers,
                null,
                bodys
            );

            // 5. 处理响应
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            log.info("短信API响应状态码: {}, 响应结果: {}", response.getStatusLine().getStatusCode(), result);

            if (response.getStatusLine().getStatusCode() != 200) {
                log.error("短信发送失败，API返回非200状态码");
                throw new RuntimeException("短信服务异常，请稍后重试");
            }

            // 6. 将验证码保存到Redis
            String redisKey = VERIFY_CODE_PREFIX + phone;
            try {
                redisTemplate.opsForValue().set(
                    redisKey,
                    code,
                    VERIFY_CODE_EXPIRE,
                    TimeUnit.SECONDS
                );

                // 验证是否成功保存到Redis
                String savedCode = redisTemplate.opsForValue().get(redisKey);
                if (savedCode == null || !savedCode.equals(code)) {
                    log.error("验证码未能正确保存到Redis，key: {}, 期望值: {}, 实际值: {}", redisKey, code, savedCode);
                    throw new RuntimeException("系统错误，请稍后重试");
                }
                log.info("验证码已成功保存到Redis，key: {}", redisKey);
            } catch (Exception e) {
                log.error("Redis操作失败: {}", e.getMessage(), e);
                throw new RuntimeException("系统错误，请稍后重试");
            }

            log.info("验证码发送完成，手机号: {}", phone);
        } catch (Exception e) {
            log.error("发送验证码过程中发生错误: {}", e.getMessage(), e);
            throw new RuntimeException("发送验证码失败: " + e.getMessage());
        }
    }
}